/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"jit/Recover.h"#include"mozilla/SizePrintfMacros.h"#include"jsapi.h"#include"jscntxt.h"#include"jsiter.h"#include"jsmath.h"#include"jsobj.h"#include"jsstr.h"#include"builtin/RegExp.h"#include"builtin/SIMD.h"#include"builtin/TypedObject.h"#include"gc/Heap.h"#include"jit/JitFrameIterator.h"#include"jit/JitSpewer.h"#include"jit/MIR.h"#include"jit/MIRGraph.h"#include"jit/VMFunctions.h"#include"vm/Interpreter.h"#include"vm/String.h"#include"vm/Interpreter-inl.h"#include"vm/NativeObject-inl.h"usingnamespacejs;usingnamespacejs::jit;boolMNode::writeRecoverData(CompactBufferWriter&writer)const{MOZ_CRASH("This instruction is not serializable");}voidRInstruction::readRecoverData(CompactBufferReader&reader,RInstructionStorage*raw){uint32_top=reader.readUnsigned();switch(Opcode(op)){# define MATCH_OPCODES_(op) \ case Recover_##op: \ static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \ "storage space must be big enough to store R" #op); \ static_assert(alignof(R##op) <= alignof(RInstructionStorage), \ "storage space must be aligned adequate to store R" #op); \ new (raw->addr()) R##op(reader); \ break;RECOVER_OPCODE_LIST(MATCH_OPCODES_)# undef MATCH_OPCODES_caseRecover_Invalid:default:MOZ_CRASH("Bad decoding of the previous instruction?");}}boolMResumePoint::writeRecoverData(CompactBufferWriter&writer)const{writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint));MBasicBlock*bb=block();JSFunction*fun=bb->info().funMaybeLazy();JSScript*script=bb->info().script();uint32_texprStack=stackDepth()-bb->info().ninvoke();#ifdef DEBUG// Ensure that all snapshot which are encoded can safely be used for// bailouts.if(GetJitContext()->cx){uint32_tstackDepth;boolreachablePC;jsbytecode*bailPC=pc();if(mode()==MResumePoint::ResumeAfter)bailPC=GetNextPc(pc());if(!ReconstructStackDepth(GetJitContext()->cx,script,bailPC,&stackDepth,&reachablePC)){returnfalse;}if(reachablePC){if(JSOp(*bailPC)==JSOP_FUNCALL){// For fun.call(this, ...); the reconstructStackDepth will// include the this. When inlining that is not included. So the// exprStackSlots will be one less.MOZ_ASSERT(stackDepth-exprStack<=1);}elseif(JSOp(*bailPC)!=JSOP_FUNAPPLY&&!IsGetPropPC(bailPC)&&!IsSetPropPC(bailPC)){// For fun.apply({}, arguments) the reconstructStackDepth will// have stackdepth 4, but it could be that we inlined the// funapply. In that case exprStackSlots, will have the real// arguments in the slots and not be 4.// With accessors, we have different stack depths depending on// whether or not we inlined the accessor, as the inlined stack// contains a callee function that should never have been there// and we might just be capturing an uneventful property site,// in which case there won't have been any violence.MOZ_ASSERT(exprStack==stackDepth);}}}#endif// Test if we honor the maximum of arguments at all times. This is a sanity// check and not an algorithm limit. So check might be a bit too loose. +4// to account for scope chain, return value, this value and maybe// arguments_object.MOZ_ASSERT(CountArgSlots(script,fun)<SNAPSHOT_MAX_NARGS+4);#ifdef JS_JITSPEWuint32_timplicit=StartArgSlot(script);#endifuint32_tformalArgs=CountArgSlots(script,fun);uint32_tnallocs=formalArgs+script->nfixed()+exprStack;JitSpew(JitSpew_IonSnapshots,"Starting frame; implicit %u, formals %u, fixed %"PRIuSIZE", exprs %u",implicit,formalArgs-implicit,script->nfixed(),exprStack);uint32_tpcoff=script->pcToOffset(pc());JitSpew(JitSpew_IonSnapshots,"Writing pc offset %u, nslots %u",pcoff,nallocs);writer.writeUnsigned(pcoff);writer.writeUnsigned(nallocs);returntrue;}RResumePoint::RResumePoint(CompactBufferReader&reader){pcOffset_=reader.readUnsigned();numOperands_=reader.readUnsigned();JitSpew(JitSpew_IonSnapshots,"Read RResumePoint (pc offset %u, nslots %u)",pcOffset_,numOperands_);}boolRResumePoint::recover(JSContext*cx,SnapshotIterator&iter)const{MOZ_CRASH("This instruction is not recoverable.");}boolMBitNot::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_BitNot));returntrue;}RBitNot::RBitNot(CompactBufferReader&reader){}boolRBitNot::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValueoperand(cx,iter.read());int32_tresult;if(!js::BitNot(cx,operand,&result))returnfalse;RootedValuerootedResult(cx,js::Int32Value(result));iter.storeInstructionResult(rootedResult);returntrue;}boolMBitAnd::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd));returntrue;}RBitAnd::RBitAnd(CompactBufferReader&reader){}boolRBitAnd::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());int32_tresult;MOZ_ASSERT(!lhs.isObject()&&!rhs.isObject());if(!js::BitAnd(cx,lhs,rhs,&result))returnfalse;RootedValuerootedResult(cx,js::Int32Value(result));iter.storeInstructionResult(rootedResult);returntrue;}boolMBitOr::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_BitOr));returntrue;}RBitOr::RBitOr(CompactBufferReader&reader){}boolRBitOr::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());int32_tresult;MOZ_ASSERT(!lhs.isObject()&&!rhs.isObject());if(!js::BitOr(cx,lhs,rhs,&result))returnfalse;RootedValueasValue(cx,js::Int32Value(result));iter.storeInstructionResult(asValue);returntrue;}boolMBitXor::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_BitXor));returntrue;}RBitXor::RBitXor(CompactBufferReader&reader){}boolRBitXor::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());int32_tresult;if(!js::BitXor(cx,lhs,rhs,&result))returnfalse;RootedValuerootedResult(cx,js::Int32Value(result));iter.storeInstructionResult(rootedResult);returntrue;}boolMLsh::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Lsh));returntrue;}RLsh::RLsh(CompactBufferReader&reader){}boolRLsh::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());int32_tresult;MOZ_ASSERT(!lhs.isObject()&&!rhs.isObject());if(!js::BitLsh(cx,lhs,rhs,&result))returnfalse;RootedValueasValue(cx,js::Int32Value(result));iter.storeInstructionResult(asValue);returntrue;}boolMRsh::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Rsh));returntrue;}RRsh::RRsh(CompactBufferReader&reader){}boolRRsh::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());MOZ_ASSERT(!lhs.isObject()&&!rhs.isObject());int32_tresult;if(!js::BitRsh(cx,lhs,rhs,&result))returnfalse;RootedValuerootedResult(cx,js::Int32Value(result));iter.storeInstructionResult(rootedResult);returntrue;}boolMUrsh::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Ursh));returntrue;}RUrsh::RUrsh(CompactBufferReader&reader){}boolRUrsh::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());MOZ_ASSERT(!lhs.isObject()&&!rhs.isObject());RootedValueresult(cx);if(!js::UrshOperation(cx,lhs,rhs,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMSignExtend::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtend));MOZ_ASSERT(Mode(uint8_t(mode_))==mode_);writer.writeByte(uint8_t(mode_));returntrue;}RSignExtend::RSignExtend(CompactBufferReader&reader){mode_=reader.readByte();}boolRSignExtend::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValueoperand(cx,iter.read());int32_tresult;switch(MSignExtend::Mode(mode_)){caseMSignExtend::Byte:if(!js::SignExtendOperation<int8_t>(cx,operand,&result))returnfalse;break;caseMSignExtend::Half:if(!js::SignExtendOperation<int16_t>(cx,operand,&result))returnfalse;break;}RootedValuerootedResult(cx,js::Int32Value(result));iter.storeInstructionResult(rootedResult);returntrue;}boolMAdd::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Add));writer.writeByte(specialization_==MIRType::Float32);returntrue;}RAdd::RAdd(CompactBufferReader&reader){isFloatOperation_=reader.readByte();}boolRAdd::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(!lhs.isObject()&&!rhs.isObject());if(!js::AddValues(cx,&lhs,&rhs,&result))returnfalse;// MIRType::Float32 is a specialization embedding the fact that the result is// rounded to a Float32.if(isFloatOperation_&&!RoundFloat32(cx,result,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMSub::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Sub));writer.writeByte(specialization_==MIRType::Float32);returntrue;}RSub::RSub(CompactBufferReader&reader){isFloatOperation_=reader.readByte();}boolRSub::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(!lhs.isObject()&&!rhs.isObject());if(!js::SubValues(cx,&lhs,&rhs,&result))returnfalse;// MIRType::Float32 is a specialization embedding the fact that the result is// rounded to a Float32.if(isFloatOperation_&&!RoundFloat32(cx,result,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMMul::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Mul));writer.writeByte(specialization_==MIRType::Float32);MOZ_ASSERT(Mode(uint8_t(mode_))==mode_);writer.writeByte(uint8_t(mode_));returntrue;}RMul::RMul(CompactBufferReader&reader){isFloatOperation_=reader.readByte();mode_=reader.readByte();}boolRMul::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());RootedValueresult(cx);if(MMul::Mode(mode_)==MMul::Normal){if(!js::MulValues(cx,&lhs,&rhs,&result))returnfalse;// MIRType::Float32 is a specialization embedding the fact that the// result is rounded to a Float32.if(isFloatOperation_&&!RoundFloat32(cx,result,&result))returnfalse;}else{MOZ_ASSERT(MMul::Mode(mode_)==MMul::Integer);if(!js::math_imul_handle(cx,lhs,rhs,&result))returnfalse;}iter.storeInstructionResult(result);returntrue;}boolMDiv::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Div));writer.writeByte(specialization_==MIRType::Float32);returntrue;}RDiv::RDiv(CompactBufferReader&reader){isFloatOperation_=reader.readByte();}boolRDiv::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());RootedValueresult(cx);if(!js::DivValues(cx,&lhs,&rhs,&result))returnfalse;// MIRType::Float32 is a specialization embedding the fact that the result is// rounded to a Float32.if(isFloatOperation_&&!RoundFloat32(cx,result,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMMod::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Mod));returntrue;}RMod::RMod(CompactBufferReader&reader){}boolRMod::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(!lhs.isObject()&&!rhs.isObject());if(!js::ModValues(cx,&lhs,&rhs,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMNot::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Not));returntrue;}RNot::RNot(CompactBufferReader&reader){}boolRNot::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuev(cx,iter.read());RootedValueresult(cx);result.setBoolean(!ToBoolean(v));iter.storeInstructionResult(result);returntrue;}boolMConcat::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Concat));returntrue;}RConcat::RConcat(CompactBufferReader&reader){}boolRConcat::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuelhs(cx,iter.read());RootedValuerhs(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(!lhs.isObject()&&!rhs.isObject());if(!js::AddValues(cx,&lhs,&rhs,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}RStringLength::RStringLength(CompactBufferReader&reader){}boolRStringLength::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValueoperand(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(!operand.isObject());if(!js::GetLengthProperty(operand,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMStringLength::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_StringLength));returntrue;}boolMArgumentsLength::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength));returntrue;}RArgumentsLength::RArgumentsLength(CompactBufferReader&reader){}boolRArgumentsLength::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValueresult(cx);result.setInt32(iter.readOuterNumActualArgs());iter.storeInstructionResult(result);returntrue;}boolMFloor::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));returntrue;}RFloor::RFloor(CompactBufferReader&reader){}boolRFloor::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuev(cx,iter.read());RootedValueresult(cx);if(!js::math_floor_handle(cx,v,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMCeil::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));returntrue;}RCeil::RCeil(CompactBufferReader&reader){}boolRCeil::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuev(cx,iter.read());RootedValueresult(cx);if(!js::math_ceil_handle(cx,v,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMRound::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));returntrue;}RRound::RRound(CompactBufferReader&reader){}boolRRound::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuearg(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(!arg.isObject());if(!js::math_round_handle(cx,arg,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMCharCodeAt::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt));returntrue;}RCharCodeAt::RCharCodeAt(CompactBufferReader&reader){}boolRCharCodeAt::recover(JSContext*cx,SnapshotIterator&iter)const{RootedStringlhs(cx,iter.read().toString());RootedValuerhs(cx,iter.read());RootedValueresult(cx);if(!js::str_charCodeAt_impl(cx,lhs,rhs,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMFromCharCode::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode));returntrue;}RFromCharCode::RFromCharCode(CompactBufferReader&reader){}boolRFromCharCode::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValueoperand(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(!operand.isObject());if(!js::str_fromCharCode_one_arg(cx,operand,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMPow::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Pow));returntrue;}RPow::RPow(CompactBufferReader&reader){}boolRPow::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuebase(cx,iter.read());RootedValuepower(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(base.isNumber()&&power.isNumber());if(!js::math_pow_handle(cx,base,power,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMPowHalf::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf));returntrue;}RPowHalf::RPowHalf(CompactBufferReader&reader){}boolRPowHalf::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuebase(cx,iter.read());RootedValuepower(cx);RootedValueresult(cx);power.setNumber(0.5);MOZ_ASSERT(base.isNumber());if(!js::math_pow_handle(cx,base,power,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMMinMax::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_MinMax));writer.writeByte(isMax_);returntrue;}RMinMax::RMinMax(CompactBufferReader&reader){isMax_=reader.readByte();}boolRMinMax::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuea(cx,iter.read());RootedValueb(cx,iter.read());RootedValueresult(cx);if(!js::minmax_impl(cx,isMax_,a,b,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMAbs::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Abs));returntrue;}RAbs::RAbs(CompactBufferReader&reader){}boolRAbs::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuev(cx,iter.read());RootedValueresult(cx);if(!js::math_abs_handle(cx,v,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMSqrt::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt));writer.writeByte(type()==MIRType::Float32);returntrue;}RSqrt::RSqrt(CompactBufferReader&reader){isFloatOperation_=reader.readByte();}boolRSqrt::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuenum(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(num.isNumber());if(!math_sqrt_handle(cx,num,&result))returnfalse;// MIRType::Float32 is a specialization embedding the fact that the result is// rounded to a Float32.if(isFloatOperation_&&!RoundFloat32(cx,result,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMAtan2::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Atan2));returntrue;}RAtan2::RAtan2(CompactBufferReader&reader){}boolRAtan2::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuey(cx,iter.read());RootedValuex(cx,iter.read());RootedValueresult(cx);if(!math_atan2_handle(cx,y,x,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMHypot::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Hypot));writer.writeUnsigned(uint32_t(numOperands()));returntrue;}RHypot::RHypot(CompactBufferReader&reader):numOperands_(reader.readUnsigned()){}boolRHypot::recover(JSContext*cx,SnapshotIterator&iter)const{JS::AutoValueVectorvec(cx);if(!vec.reserve(numOperands_))returnfalse;for(uint32_ti=0;i<numOperands_;++i)vec.infallibleAppend(iter.read());RootedValueresult(cx);if(!js::math_hypot_handle(cx,vec,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMMathFunction::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());switch(function_){caseRound:writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));returntrue;caseSin:caseLog:writer.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction));writer.writeByte(function_);returntrue;default:MOZ_CRASH("Unknown math function.");}}RMathFunction::RMathFunction(CompactBufferReader&reader){function_=reader.readByte();}boolRMathFunction::recover(JSContext*cx,SnapshotIterator&iter)const{switch(function_){caseMMathFunction::Sin:{RootedValuearg(cx,iter.read());RootedValueresult(cx);if(!js::math_sin_handle(cx,arg,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}caseMMathFunction::Log:{RootedValuearg(cx,iter.read());RootedValueresult(cx);if(!js::math_log_handle(cx,arg,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}default:MOZ_CRASH("Unknown math function.");}}boolMRandom::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(this->canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Random));returntrue;}RRandom::RRandom(CompactBufferReader&reader){}boolRRandom::recover(JSContext*cx,SnapshotIterator&iter)const{iter.storeInstructionResult(DoubleValue(math_random_impl(cx)));returntrue;}boolMStringSplit::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit));returntrue;}RStringSplit::RStringSplit(CompactBufferReader&reader){}boolRStringSplit::recover(JSContext*cx,SnapshotIterator&iter)const{RootedStringstr(cx,iter.read().toString());RootedStringsep(cx,iter.read().toString());RootedObjectGroupgroup(cx,ObjectGroupCompartment::getStringSplitStringGroup(cx));if(!group){returnfalse;}RootedValueresult(cx);JSObject*res=str_split_string(cx,group,str,sep,INT32_MAX);if(!res)returnfalse;result.setObject(*res);iter.storeInstructionResult(result);returntrue;}boolMNaNToZero::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero));returntrue;}RNaNToZero::RNaNToZero(CompactBufferReader&reader){}boolRNaNToZero::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuev(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(v.isDouble()||v.isInt32());// x ? x : 0.0if(ToBoolean(v))result=v;elseresult.setDouble(0.0);iter.storeInstructionResult(result);returntrue;}boolMRegExpMatcher::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpMatcher));returntrue;}RRegExpMatcher::RRegExpMatcher(CompactBufferReader&reader){}boolRRegExpMatcher::recover(JSContext*cx,SnapshotIterator&iter)const{RootedObjectregexp(cx,&iter.read().toObject());RootedStringinput(cx,iter.read().toString());int32_tlastIndex=iter.read().toInt32();RootedValueresult(cx);if(!RegExpMatcherRaw(cx,regexp,input,lastIndex,nullptr,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMRegExpSearcher::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpSearcher));returntrue;}RRegExpSearcher::RRegExpSearcher(CompactBufferReader&reader){}boolRRegExpSearcher::recover(JSContext*cx,SnapshotIterator&iter)const{RootedObjectregexp(cx,&iter.read().toObject());RootedStringinput(cx,iter.read().toString());int32_tlastIndex=iter.read().toInt32();int32_tresult;if(!RegExpSearcherRaw(cx,regexp,input,lastIndex,nullptr,&result))returnfalse;RootedValueresultVal(cx);resultVal.setInt32(result);iter.storeInstructionResult(resultVal);returntrue;}boolMRegExpTester::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpTester));returntrue;}RRegExpTester::RRegExpTester(CompactBufferReader&reader){}boolRRegExpTester::recover(JSContext*cx,SnapshotIterator&iter)const{RootedStringstring(cx,iter.read().toString());RootedObjectregexp(cx,&iter.read().toObject());int32_tlastIndex=iter.read().toInt32();int32_tendIndex;if(!js::RegExpTesterRaw(cx,regexp,string,lastIndex,&endIndex))returnfalse;RootedValueresult(cx);result.setInt32(endIndex);iter.storeInstructionResult(result);returntrue;}boolMTypeOf::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf));returntrue;}RTypeOf::RTypeOf(CompactBufferReader&reader){}boolRTypeOf::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuev(cx,iter.read());RootedValueresult(cx,StringValue(TypeOfOperation(v,cx->runtime())));iter.storeInstructionResult(result);returntrue;}boolMToDouble::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble));returntrue;}RToDouble::RToDouble(CompactBufferReader&reader){}boolRToDouble::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuev(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(!v.isObject());MOZ_ASSERT(!v.isSymbol());doubledbl;if(!ToNumber(cx,v,&dbl))returnfalse;result.setDouble(dbl);iter.storeInstructionResult(result);returntrue;}boolMToFloat32::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32));returntrue;}RToFloat32::RToFloat32(CompactBufferReader&reader){}boolRToFloat32::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuev(cx,iter.read());RootedValueresult(cx);MOZ_ASSERT(!v.isObject());if(!RoundFloat32(cx,v,&result))returnfalse;iter.storeInstructionResult(result);returntrue;}boolMTruncateToInt32::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32));returntrue;}RTruncateToInt32::RTruncateToInt32(CompactBufferReader&reader){}boolRTruncateToInt32::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValuevalue(cx,iter.read());RootedValueresult(cx);int32_ttrunc;if(!JS::ToInt32(cx,value,&trunc))returnfalse;result.setInt32(trunc);iter.storeInstructionResult(result);returntrue;}boolMNewObject::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_NewObject));MOZ_ASSERT(Mode(uint8_t(mode_))==mode_);writer.writeByte(uint8_t(mode_));returntrue;}RNewObject::RNewObject(CompactBufferReader&reader){mode_=MNewObject::Mode(reader.readByte());}boolRNewObject::recover(JSContext*cx,SnapshotIterator&iter)const{RootedObjecttemplateObject(cx,&iter.read().toObject());RootedValueresult(cx);JSObject*resultObject=nullptr;// See CodeGenerator::visitNewObjectVMCallswitch(mode_){caseMNewObject::ObjectLiteral:resultObject=NewObjectOperationWithTemplate(cx,templateObject);break;caseMNewObject::ObjectCreate:resultObject=ObjectCreateWithTemplate(cx,templateObject.as<PlainObject>());break;}if(!resultObject)returnfalse;result.setObject(*resultObject);iter.storeInstructionResult(result);returntrue;}boolMNewTypedArray::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray));returntrue;}RNewTypedArray::RNewTypedArray(CompactBufferReader&reader){}boolRNewTypedArray::recover(JSContext*cx,SnapshotIterator&iter)const{RootedObjecttemplateObject(cx,&iter.read().toObject());RootedValueresult(cx);uint32_tlength=templateObject.as<TypedArrayObject>()->length();JSObject*resultObject=TypedArrayCreateWithTemplate(cx,templateObject,length);if(!resultObject)returnfalse;result.setObject(*resultObject);iter.storeInstructionResult(result);returntrue;}boolMNewArray::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray));writer.writeUnsigned(length());returntrue;}RNewArray::RNewArray(CompactBufferReader&reader){count_=reader.readUnsigned();}boolRNewArray::recover(JSContext*cx,SnapshotIterator&iter)const{RootedObjecttemplateObject(cx,&iter.read().toObject());RootedValueresult(cx);RootedObjectGroupgroup(cx,templateObject->group());JSObject*resultObject=NewFullyAllocatedArrayTryUseGroup(cx,group,count_);if(!resultObject)returnfalse;result.setObject(*resultObject);iter.storeInstructionResult(result);returntrue;}boolMNewIterator::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator));writer.writeByte(type_);returntrue;}RNewIterator::RNewIterator(CompactBufferReader&reader){type_=reader.readByte();}boolRNewIterator::recover(JSContext*cx,SnapshotIterator&iter)const{RootedObjecttemplateObject(cx,&iter.read().toObject());RootedValueresult(cx);JSObject*resultObject=nullptr;switch(MNewIterator::Type(type_)){caseMNewIterator::ArrayIterator:resultObject=NewArrayIteratorObject(cx);break;caseMNewIterator::StringIterator:resultObject=NewStringIteratorObject(cx);break;}if(!resultObject)returnfalse;result.setObject(*resultObject);iter.storeInstructionResult(result);returntrue;}boolMNewDerivedTypedObject::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_NewDerivedTypedObject));returntrue;}RNewDerivedTypedObject::RNewDerivedTypedObject(CompactBufferReader&reader){}boolRNewDerivedTypedObject::recover(JSContext*cx,SnapshotIterator&iter)const{Rooted<TypeDescr*>descr(cx,&iter.read().toObject().as<TypeDescr>());Rooted<TypedObject*>owner(cx,&iter.read().toObject().as<TypedObject>());int32_toffset=iter.read().toInt32();JSObject*obj=OutlineTypedObject::createDerived(cx,descr,owner,offset);if(!obj)returnfalse;RootedValueresult(cx,ObjectValue(*obj));iter.storeInstructionResult(result);returntrue;}boolMCreateThisWithTemplate::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_CreateThisWithTemplate));returntrue;}RCreateThisWithTemplate::RCreateThisWithTemplate(CompactBufferReader&reader){}boolRCreateThisWithTemplate::recover(JSContext*cx,SnapshotIterator&iter)const{RootedObjecttemplateObject(cx,&iter.read().toObject());// See CodeGenerator::visitCreateThisWithTemplateJSObject*resultObject=NewObjectOperationWithTemplate(cx,templateObject);if(!resultObject)returnfalse;RootedValueresult(cx);result.setObject(*resultObject);iter.storeInstructionResult(result);returntrue;}boolMLambda::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_Lambda));returntrue;}RLambda::RLambda(CompactBufferReader&reader){}boolRLambda::recover(JSContext*cx,SnapshotIterator&iter)const{RootedObjectscopeChain(cx,&iter.read().toObject());RootedFunctionfun(cx,&iter.read().toObject().as<JSFunction>());JSObject*resultObject=js::Lambda(cx,fun,scopeChain);if(!resultObject)returnfalse;RootedValueresult(cx);result.setObject(*resultObject);iter.storeInstructionResult(result);returntrue;}boolMLambdaArrow::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_LambdaArrow));returntrue;}RLambdaArrow::RLambdaArrow(CompactBufferReader&reader){}boolRLambdaArrow::recover(JSContext*cx,SnapshotIterator&iter)const{RootedObjectscopeChain(cx,&iter.read().toObject());RootedValuenewTarget(cx,iter.read());RootedFunctionfun(cx,&iter.read().toObject().as<JSFunction>());JSObject*resultObject=js::LambdaArrow(cx,fun,scopeChain,newTarget);if(!resultObject)returnfalse;RootedValueresult(cx);result.setObject(*resultObject);iter.storeInstructionResult(result);returntrue;}boolMSimdBox::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_SimdBox));static_assert(unsigned(SimdType::Count)<0x100,"assuming SimdType fits in 8 bits");writer.writeByte(uint8_t(simdType()));returntrue;}RSimdBox::RSimdBox(CompactBufferReader&reader){type_=reader.readByte();}boolRSimdBox::recover(JSContext*cx,SnapshotIterator&iter)const{JSObject*resultObject=nullptr;RValueAllocationa=iter.readAllocation();MOZ_ASSERT(iter.allocationReadable(a));MOZ_ASSERT_IF(a.mode()==RValueAllocation::ANY_FLOAT_REG,a.fpuReg().isSimd128());constFloatRegisters::RegisterContent*raw=iter.floatAllocationPointer(a);switch(SimdType(type_)){caseSimdType::Bool8x16:resultObject=js::CreateSimd<Bool8x16>(cx,(constBool8x16::Elem*)raw);break;caseSimdType::Int8x16:resultObject=js::CreateSimd<Int8x16>(cx,(constInt8x16::Elem*)raw);break;caseSimdType::Uint8x16:resultObject=js::CreateSimd<Uint8x16>(cx,(constUint8x16::Elem*)raw);break;caseSimdType::Bool16x8:resultObject=js::CreateSimd<Bool16x8>(cx,(constBool16x8::Elem*)raw);break;caseSimdType::Int16x8:resultObject=js::CreateSimd<Int16x8>(cx,(constInt16x8::Elem*)raw);break;caseSimdType::Uint16x8:resultObject=js::CreateSimd<Uint16x8>(cx,(constUint16x8::Elem*)raw);break;caseSimdType::Bool32x4:resultObject=js::CreateSimd<Bool32x4>(cx,(constBool32x4::Elem*)raw);break;caseSimdType::Int32x4:resultObject=js::CreateSimd<Int32x4>(cx,(constInt32x4::Elem*)raw);break;caseSimdType::Uint32x4:resultObject=js::CreateSimd<Uint32x4>(cx,(constUint32x4::Elem*)raw);break;caseSimdType::Float32x4:resultObject=js::CreateSimd<Float32x4>(cx,(constFloat32x4::Elem*)raw);break;caseSimdType::Float64x2:MOZ_CRASH("NYI, RSimdBox of Float64x2");break;caseSimdType::Bool64x2:MOZ_CRASH("NYI, RSimdBox of Bool64x2");break;caseSimdType::Count:MOZ_CRASH("RSimdBox of Count is unreachable");}if(!resultObject)returnfalse;RootedValueresult(cx);result.setObject(*resultObject);iter.storeInstructionResult(result);returntrue;}boolMObjectState::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState));writer.writeUnsigned(numSlots());returntrue;}RObjectState::RObjectState(CompactBufferReader&reader){numSlots_=reader.readUnsigned();}boolRObjectState::recover(JSContext*cx,SnapshotIterator&iter)const{RootedObjectobject(cx,&iter.read().toObject());RootedValueval(cx);if(object->is<UnboxedPlainObject>()){constUnboxedLayout&layout=object->as<UnboxedPlainObject>().layout();RootedIdid(cx);RootedValuereceiver(cx,ObjectValue(*object));constUnboxedLayout::PropertyVector&properties=layout.properties();for(size_ti=0;i<properties.length();i++){val=iter.read();// This is the default placeholder value of MObjectState, when no// properties are defined yet.if(val.isUndefined())continue;id=NameToId(properties[i].name);ObjectOpResultresult;// SetProperty can only fail due to OOM.if(!SetProperty(cx,object,id,val,receiver,result))returnfalse;if(!result)returnresult.reportError(cx,object,id);}}else{RootedNativeObjectnativeObject(cx,&object->as<NativeObject>());MOZ_ASSERT(nativeObject->slotSpan()==numSlots());for(size_ti=0;i<numSlots();i++){val=iter.read();nativeObject->setSlot(i,val);}}val.setObject(*object);iter.storeInstructionResult(val);returntrue;}boolMArrayState::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState));writer.writeUnsigned(numElements());returntrue;}RArrayState::RArrayState(CompactBufferReader&reader){numElements_=reader.readUnsigned();}boolRArrayState::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValueresult(cx);ArrayObject*object=&iter.read().toObject().as<ArrayObject>();uint32_tinitLength=iter.read().toInt32();object->setDenseInitializedLength(initLength);for(size_tindex=0;index<numElements();index++){Valueval=iter.read();if(index>=initLength){MOZ_ASSERT(val.isUndefined());continue;}object->initDenseElement(index,val);}result.setObject(*object);iter.storeInstructionResult(result);returntrue;}boolMAssertRecoveredOnBailout::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout()==mustBeRecovered_,"assertRecoveredOnBailout failed during compilation");writer.writeUnsigned(uint32_t(RInstruction::Recover_AssertRecoveredOnBailout));returntrue;}RAssertRecoveredOnBailout::RAssertRecoveredOnBailout(CompactBufferReader&reader){}boolRAssertRecoveredOnBailout::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValueresult(cx);iter.read();// skip the unused operand.result.setUndefined();iter.storeInstructionResult(result);returntrue;}boolMStringReplace::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace));writer.writeByte(isFlatReplacement_);returntrue;}RStringReplace::RStringReplace(CompactBufferReader&reader){isFlatReplacement_=reader.readByte();}boolRStringReplace::recover(JSContext*cx,SnapshotIterator&iter)const{RootedStringstring(cx,iter.read().toString());RootedStringpattern(cx,iter.read().toString());RootedStringreplace(cx,iter.read().toString());JSString*result=isFlatReplacement_?js::str_flat_replace_string(cx,string,pattern,replace):js::str_replace_string_raw(cx,string,pattern,replace);if(!result)returnfalse;iter.storeInstructionResult(StringValue(result));returntrue;}boolMAtomicIsLockFree::writeRecoverData(CompactBufferWriter&writer)const{MOZ_ASSERT(canRecoverOnBailout());writer.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree));returntrue;}RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader&reader){}boolRAtomicIsLockFree::recover(JSContext*cx,SnapshotIterator&iter)const{RootedValueoperand(cx,iter.read());MOZ_ASSERT(operand.isInt32());int32_tresult;if(!js::AtomicIsLockFree(cx,operand,&result))returnfalse;RootedValuerootedResult(cx,js::Int32Value(result));iter.storeInstructionResult(rootedResult);returntrue;}